package com.gc.materialdesign.views;

import com.gc.materialdesign.utils.ShapeUtil;
import com.gc.materialdesign.utils.Utils;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.*;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.media.image.PixelMap;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Size;
import ohos.multimodalinput.event.MmiPoint;
import ohos.multimodalinput.event.TouchEvent;

public class LayoutRipple extends CustomView implements Component.FocusChangedListener, Component.TouchEventListener {
    private float rippleSpeed = 20f;
    private int rippleSize = 3;

    private ClickedListener onClickListener;
    private String backgroundColor = "#FFFFFF";

    private String rippleColor;
    private Float xRippleOrigin;
    private Float yRippleOrigin;

    public LayoutRipple(Context context) {
        this(context, null);
    }

    public LayoutRipple(Context context, AttrSet attrs) {
        this(context, attrs, null);
    }

    public LayoutRipple(Context context, AttrSet attrs, String defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setAttributes(attrs);
        setFocusChangedListener(this);
        setTouchEventListener(this);
    }

    // Set atributtes of XML to View
    protected void setAttributes(AttrSet attrs) {
        // Set background Color
        // Color by resource
        boolean backgroundIsPresent = attrs.getAttr("background").isPresent();
        if (backgroundIsPresent) {
            String color = attrs.getAttr("background").get().getStringValue();
            setBackgroundColor(color);
            setBackground(ShapeUtil.createDrawable(Color.getIntColor(Utils.rgba(color))));
        } else {
            setBackgroundColor(backgroundColor);
            setBackground(ShapeUtil.createDrawable(Color.getIntColor(Utils.rgba(backgroundColor))));
        }
        // Set Ripple Color
        // Color by resource
        boolean rippleColorIsPresent = attrs.getAttr("rippleColor").isPresent();
        if (rippleColorIsPresent) {
            String rippleColor = attrs.getAttr("rippleColor").get().getStringValue();
            setRippleColor(rippleColor);
        } else {
            setRippleColor(makePressColorString());
        }

        boolean rippleSpeedIsPresent = attrs.getAttr("rippleSpeed").isPresent();
        if (rippleSpeedIsPresent) {
            rippleSpeed = attrs.getAttr("rippleSpeed").get().getFloatValue();
        }
    }

    // Set color of background
    public void setBackgroundColor(String color) {
        this.backgroundColor = color;
        if (isEnabled()) {
            beforeBackground = backgroundColor;
        }
    }

    public void setRippleSpeed(int rippleSpeed) {
        this.rippleSpeed = rippleSpeed;
    }

    // ### RIPPLE EFFECT ###

    private float x = -1, y = -1;
    private float radius = -1;

    @Override
    public boolean onTouchEvent(Component component, TouchEvent event) {
        invalidate();
        if (isEnabled()) {
            isLastTouch = true;
            MmiPoint mmiPoint = event.getPointerScreenPosition(event.getIndex());
            if (event.getAction() == TouchEvent.PRIMARY_POINT_DOWN) {
                radius = getHeight() / rippleSize;
                x = Math.abs(mmiPoint.getX() - getLocationOnScreen()[0]);
                y = Math.abs(mmiPoint.getY() - getLocationOnScreen()[1]);
            } else if (event.getAction() == TouchEvent.POINT_MOVE) {
                radius = getHeight() / rippleSize;
                x = Math.abs(mmiPoint.getX() - getLocationOnScreen()[0]);
                y = Math.abs(mmiPoint.getY() - getLocationOnScreen()[1]);
                if (!(x <= getWidth() && y <= getHeight())) {
                    isLastTouch = false;
                    x = -1;
                    y = -1;
                }
            } else if (event.getAction() == TouchEvent.PRIMARY_POINT_UP) {
                if (Math.abs(mmiPoint.getX() - getLocationOnScreen()[0]) <= getWidth()
                        && Math.abs(mmiPoint.getY() - getLocationOnScreen()[1]) <= getHeight()) {
                    radius++;
                } else {
                    isLastTouch = false;
                    x = -1;
                    y = -1;
                }
            }
            if (event.getAction() == TouchEvent.CANCEL) {
                isLastTouch = false;
                x = -1;
                y = -1;
            }
        }
        return true;
    }

    @Override
    public void onFocusChange(Component component, boolean gainFocus) {
        if (!gainFocus) {
            x = -1;
            y = -1;
        }
    }

    public PixelMap makeCircle() {
        PixelMap.InitializationOptions initializationOptions = new PixelMap.InitializationOptions();
        initializationOptions.pixelFormat = PixelFormat.ARGB_8888;
        initializationOptions.size = new Size(getWidth(), getHeight());
        PixelMap pixelMap = PixelMap.create(initializationOptions);

        Texture texture = new Texture(pixelMap);
        Canvas canvas = new Canvas(texture);

        Paint paint = new Paint();
        paint.setAntiAlias(true);
        if (rippleColor == null) {
            rippleColor = makePressColorString();
        }
        paint.setColor(new Color(Color.getIntColor(Utils.argb(rippleColor))));
        paint.setAlpha(0.7f);
        x = (xRippleOrigin == null) ? x : xRippleOrigin;
        y = (yRippleOrigin == null) ? y : yRippleOrigin;
        canvas.drawCircle(x, y, radius, paint);
        if (radius > getHeight() / rippleSize) {
            radius += rippleSpeed;
        }
        if (radius >= getWidth()) {
            x = -1;
            y = -1;
            radius = getHeight() / rippleSize;
            if (onClickListener != null) {
                onClickListener.onClick(this);
            }
        }
        return texture.getPixelMap();
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        super.onDraw(component, canvas);
        if (x != -1) {
            RectFloat src = new RectFloat(0, 0, getWidth(), getHeight());
            RectFloat dst = new RectFloat(0, 0, getWidth(), getHeight());
            Paint paint = new Paint();
            canvas.drawPixelMapHolderRect(new PixelMapHolder(makeCircle()), src, dst, paint);
            getContext().getUITaskDispatcher().asyncDispatch(this::invalidate);
        }
    }

    /**
     * Make a dark color to ripple effect
     *
     * @return 改变后的颜色值
     */
    protected String makePressColorString() {
        int colorInt;
        if (backgroundColor.length() == 7) {
            colorInt = Color.getIntColor(backgroundColor);
        } else {
            colorInt = Color.getIntColor(backgroundColor.substring(0, backgroundColor.length() - 2));
        }
        int r = (colorInt >> 16) & 0xFF;
        int g = (colorInt >> 8) & 0xFF;
        int b = (colorInt >> 0) & 0xFF;
        r = Math.max(r - 30, 0);
        g = Math.max(g - 30, 0);
        b = Math.max(b - 30, 0);
        StringBuilder builder =
                new StringBuilder("#")
                        .append(colorPrefix(Integer.toHexString(r)))
                        .append(colorPrefix(Integer.toHexString(g)))
                        .append(colorPrefix(Integer.toHexString(b)));
        return builder.toString();
    }

    private String colorPrefix(String string) {
        return string.length() > 1 ? string : "00";
    }

    @Override
    public void setClickedListener(ClickedListener listener) {
        onClickListener = listener;
    }

    public void setRippleColor(String rgba) {
        rippleColor = rgba;
    }

    public void setxRippleOrigin(Float xRippleOrigin) {
        this.xRippleOrigin = xRippleOrigin;
    }

    public void setyRippleOrigin(Float yRippleOrigin) {
        this.yRippleOrigin = yRippleOrigin;
    }
}
